home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload Trio 2 / Shareware Overload Trio Volume 2 (Chestnut CD-ROM).ISO / dir24 / psi110g.zip / BOOTP.C < prev    next >
C/C++ Source or Header  |  1994-04-17  |  11KB  |  374 lines

  1. /*
  2.  * Center for Information Technology Integration
  3.  *           The University of Michigan
  4.  *                    Ann Arbor
  5.  *
  6.  * Dedicated to the public domain.
  7.  * Send questions to info@citi.umich.edu
  8.  *
  9.  * BOOTP is documented in RFC 951 and RFC 1048
  10.  * Delinted, ANSIfied and reformatted - 5/30/91 P. Karn
  11.  */
  12.   
  13.   
  14. #include <time.h>
  15. #include "global.h"
  16. #ifdef BOOTP
  17. #include "mbuf.h"
  18. #include "socket.h"
  19. #include "netuser.h"
  20. #include "udp.h"
  21. #include "iface.h"
  22. #include "ip.h"
  23. #include "internet.h"
  24. #include "domain.h"
  25. #include "rip.h"
  26. #include "cmdparse.h"
  27. #include "bootp.h"
  28.   
  29. static int bootp_rx __ARGS((struct iface *ifp,struct mbuf *bp));
  30. static void ntoh_bootp __ARGS((struct mbuf **bpp,struct bootp *bootpp));
  31. static int mask2width __ARGS((int32 mask));
  32.   
  33. #define BOOTP_TIMEOUT   30      /* Time limit for booting       */
  34. #define BOOTP_RETRANS   5       /* The inteval between sendings */
  35.   
  36. #ifdef  BOOTP
  37. int WantBootp = 0;
  38. #endif
  39. static int SilentStartup = 0;
  40.   
  41. int
  42. dobootp(argc,argv,p)
  43. int argc;
  44. char *argv[];
  45. void *p;
  46. {
  47.     struct iface *ifp = NULLIF;
  48.     struct socket lsock, fsock;
  49.     struct mbuf *bp;
  50.     struct udp_cb *bootp_cb;
  51.     register char *cp;
  52.     time_t        now,      /* The current time (seconds)   */
  53.     starttime,    /* The start time of sending BOOTP */
  54.     lastsendtime; /* The last time of sending BOOTP  */
  55.     int i;
  56.   
  57.     if(argc < 2)            /* default to the first interface */
  58.         ifp = Ifaces;
  59.     else {
  60.         for(i = 1; i != argc; ++i){
  61.   
  62.             if((ifp = if_lookup(argv[i])) != NULLIF)
  63.                 continue;
  64.             else if(strncmp(argv[i], "silent", strlen(argv[i])) == 0)
  65.                 SilentStartup = 1;
  66.             else if(strncmp(argv[i], "noisy", strlen(argv[i])) == 0)
  67.                 SilentStartup = 0;
  68.             else {
  69.                 tprintf("bootp [net_name] [silent] [noisy]\n");
  70.                 return 1;
  71.             }
  72.         }
  73.     }
  74.   
  75.     if(ifp == NULLIF)
  76.         return 0;
  77.   
  78.     lsock.address = ifp->addr;
  79.     lsock.port = IPPORT_BOOTPC;
  80.   
  81.     bootp_cb = open_udp(&lsock,NULLVFP);
  82.   
  83.     fsock.address = ifp->broadcast;
  84.     fsock.port = IPPORT_BOOTPS;
  85.   
  86.     /* Get boot starting time */
  87.     time(&starttime);
  88.     lastsendtime = 0;
  89.   
  90.     /* Send the bootp request packet until a response is received or time
  91.        out */
  92.     for(;;){
  93.   
  94.         /* Allow bootp packets should be passed through iproute. */
  95.         WantBootp = 1;
  96.   
  97.         /* Get the current time */
  98.         time(&now);
  99.   
  100.         /* Stop, if time out */
  101.         if(now - starttime >= BOOTP_TIMEOUT){
  102.             tprintf("bootp: timed out, values not set\n");
  103.             break;
  104.         }
  105.   
  106.         /* Don't flood the network, send in intervals */
  107.         if(now - lastsendtime > BOOTP_RETRANS){
  108.             if(!SilentStartup) tprintf("Requesting...\n");
  109.   
  110.             /* Allocate BOOTP packet and fill it in */
  111.             if((bp = alloc_mbuf(sizeof(struct bootp))) == NULLBUF)
  112.                 break;
  113.   
  114.             cp = bp->data;      /* names per the RFC: */
  115.             *cp++ = BOOTREQUEST;        /* op */
  116.             *cp++ = ifp->iftype->type;  /* htype */
  117.             *cp++ = ifp->iftype->hwalen;    /* hlen */
  118.             *cp++ = 0;          /* hops */
  119.             cp = put32(cp,(int32) now); /* xid */
  120.             cp = put16(cp, now - starttime);/* secs */
  121.             cp = put16(cp, 0);      /* unused */
  122.             cp = put32(cp, ifp->addr);  /* ciaddr */
  123.             cp = put32(cp, 0L);     /* yiaddr */
  124.             cp = put32(cp, 0L);     /* siaddr */
  125.             cp = put32(cp, 0L);     /* giaddr */
  126.             memcpy(cp, ifp->hwaddr, ifp->iftype->hwalen);
  127.             cp += 16;           /* chaddr */
  128.             memset(cp, 0, 64);      /* sname */
  129.             cp += 64;
  130.             memset(cp, 0, 128);     /* file */
  131.             cp += 128;
  132.             memset(cp, 0, 64);      /* vend */
  133.             cp += 64;
  134.             bp->cnt = cp - bp->data;
  135.             /* assert(bp->cnt == BOOTP_LEN) */
  136.   
  137.             /* Send out one BOOTP Request packet as a broadcast */
  138.             send_udp(&lsock, &fsock,0,0,bp,bp->cnt,0,0);
  139.   
  140.             lastsendtime = now;
  141.         }
  142.   
  143.         /* Give other tasks a chance to run. */
  144.         pwait(NULL);
  145.   
  146.         /* Test for and process any replies */
  147.         if(recv_udp(bootp_cb, &fsock, &bp) > -1){
  148.             if(bootp_rx(ifp,bp))
  149.                 break;
  150.         } else if(Net_error != WOULDBLK){
  151.             tprintf("bootp: Net_error %d, no values set\n",
  152.             Net_error);
  153.             break;
  154.         }
  155.     }
  156.   
  157.     WantBootp = 0;
  158.     del_udp(bootp_cb);
  159.     return 0;
  160. }
  161.   
  162. /* Process BOOTP input received from 'interface'. */
  163. static int
  164. bootp_rx(ifp,bp)
  165. struct iface *ifp;
  166. struct mbuf *bp;
  167. {
  168.     int         ch;
  169.     int         count;
  170.     int32       gateway = 0;
  171.     int32       nameserver = 0;
  172.     int32       broadcast, netmask;
  173.     struct route    *rp;
  174.     struct bootp    reply;
  175.     char        *cp;
  176.   
  177.     if(len_p(bp) != sizeof(struct bootp)){
  178.         free_p(bp);
  179.         return 0;
  180.     }
  181.     ntoh_bootp(&bp, &reply);
  182.     free_p(bp);
  183.   
  184.     if(reply.op != BOOTREPLY)
  185.         return 0;
  186.   
  187.     if(!SilentStartup)
  188.         tprintf("Network %s configured:\n", ifp->name);
  189.   
  190.     if(ifp->addr == 0){
  191.         Ip_addr = (int) reply.yiaddr.s_addr;    /* yiaddr */
  192.         ifp->addr =  reply.yiaddr.s_addr;   /* yiaddr */
  193.         if(!SilentStartup)
  194.             tprintf("     IP address: %s\n",
  195.             inet_ntoa(ifp->addr));
  196.     }
  197.   
  198.   
  199.     /* now process the vendor-specific block, check for cookie first. */
  200.     cp = reply.vend;
  201.     if(get32(cp) != 0x63825363L){
  202.         printf("Invalid magic cookie.\n");
  203.         return(0);
  204.     }
  205.   
  206.     cp += 4;
  207.     while(((ch = *cp) != BOOTP_END) && (++cp < (reply.vend + 64)))
  208.     switch(ch){
  209.         case BOOTP_PAD:     /* They're just padding */
  210.             continue;
  211.         case BOOTP_SUBNET:  /* fixed length, 4 octets */
  212.             cp++;       /* moved past length */
  213.   
  214.             /* Set the netmask */
  215.                 /* Remove old entry if it exists */
  216.             netmask = get32(cp);
  217.             cp += 4;
  218.   
  219.             rp = rt_blookup(ifp->addr & ifp->netmask,mask2width(ifp->netmask));
  220.             if(rp != NULLROUTE)
  221.                 rt_drop(rp->target,rp->bits);
  222.             ifp->netmask = netmask;
  223.             rt_add(ifp->addr,mask2width(ifp->netmask),0L,ifp,0L,0L,0);
  224.   
  225.             if(!SilentStartup)
  226.                 tprintf("     Subnet mask: %s\n", inet_ntoa(netmask));
  227.   
  228.             /* Set the broadcast */
  229.             broadcast = ifp->addr | ~(ifp->netmask);
  230.             rp = rt_blookup(ifp->broadcast,32);
  231.             if(rp != NULLROUTE && rp->iface == ifp)
  232.                 rt_drop(ifp->broadcast,32);
  233.             ifp->broadcast = broadcast;
  234.             rt_add(ifp->broadcast,32,0L,ifp,1L,0L,1);
  235.   
  236.             if(!SilentStartup)
  237.                 tprintf("     Broadcast: %s\n", inet_ntoa(broadcast));
  238.   
  239.             break;
  240.         case BOOTP_HOSTNAME:
  241.             count = (int) *cp;
  242.             cp++;
  243.   
  244.             if(Hostname != NULLCHAR)
  245.                 free(Hostname);
  246.             Hostname = mallocw(count);
  247.             strncpy(Hostname, cp, count);
  248.             cp += count;
  249.   
  250.             if(!SilentStartup)
  251.                 tprintf("     Hostname: %s\n", Hostname);
  252.             break;
  253.         case BOOTP_DNS:
  254.             count = (int) *cp;
  255.             cp++;
  256.   
  257.             while(count){
  258.                 nameserver = get32(cp);
  259.                 add_nameserver(nameserver,0);
  260.                 if(!SilentStartup)
  261.                     tprintf("     Nameserver: %s\n", inet_ntoa(nameserver));
  262.                 cp += 4;
  263.                 count -= 4;
  264.             }
  265.             break;
  266.         case BOOTP_GATEWAY:
  267.             count = (int) *cp;
  268.             cp++;
  269.   
  270.             gateway = get32(cp);
  271.   
  272.             /* Add the gateway as the default */
  273.             rt_add(0,0,gateway,ifp,1,0,0);
  274.   
  275.             if(!SilentStartup)
  276.                 tprintf("     Default gateway: %s\n", inet_ntoa(gateway));
  277.             cp += count;
  278.             break;
  279.         default:        /* variable field we don't know about */
  280.             count = (int) *cp;
  281.             cp++;
  282.   
  283.             cp += count;
  284.             break;
  285.     }
  286.   
  287.     rt_add(ifp->addr,mask2width(ifp->netmask),0L,ifp,1,0,0);
  288.   
  289.     return(1);
  290. }
  291.   
  292.   
  293. static void
  294. ntoh_bootp(bpp, bootpp)
  295. struct mbuf **bpp;
  296. struct bootp *bootpp;
  297. {
  298.     bootpp->op = pullchar(bpp);                     /* op */
  299.     bootpp->htype = pullchar(bpp);          /* htype */
  300.     bootpp->hlen = pullchar(bpp);           /* hlen */
  301.     bootpp->hops = pullchar(bpp);           /* hops */
  302.     bootpp->xid = pull32(bpp);          /* xid */
  303.     bootpp->secs = pull16(bpp);         /* secs */
  304.     bootpp->unused = pull16(bpp);           /* unused */
  305.     bootpp->ciaddr.s_addr = pull32(bpp);        /* ciaddr */
  306.     bootpp->yiaddr.s_addr = pull32(bpp);        /* ciaddr */
  307.     bootpp->siaddr.s_addr = pull32(bpp);        /* siaddr */
  308.     bootpp->giaddr.s_addr = pull32(bpp);        /* giaddr */
  309.     pullup(bpp, bootpp->chaddr, 16);        /* chaddr */
  310.     pullup(bpp, bootpp->sname, 64);     /* sname */
  311.     pullup(bpp, bootpp->file, 128);     /* file name */
  312.     pullup(bpp, bootpp->vend, 64);          /* vendor */
  313. }
  314.   
  315.   
  316.   
  317. #ifdef  BOOTP
  318.   
  319. int
  320. bootp_validPacket(ip, bpp)
  321. struct ip *ip;
  322. struct mbuf **bpp;
  323. {
  324.     struct udp udp;
  325.     struct pseudo_header ph;
  326.     int status;
  327.   
  328.   
  329.     /* Must be a udp packet */
  330.     if(ip->protocol !=  UDP_PTCL)
  331.         return 0;
  332.   
  333.     /* Invalid if packet is not the right size */
  334.     if(len_p(*bpp) != (sizeof(struct udp) + sizeof(struct bootp)))
  335.         return 0;
  336.   
  337.     /* Invalid if not a udp bootp packet */
  338.     ntohudp(&udp, bpp);
  339.   
  340.     status = (udp.dest == IPPORT_BOOTPC) ? 1 : 0;
  341.   
  342.     /* Restore packet, data hasn't changed */
  343.         /* Create pseudo-header and verify checksum */
  344.     ph.source = ip->source;
  345.     ph.dest = ip->dest;
  346.     ph.protocol = ip->protocol;
  347.     ph.length = ip->length - IPLEN - ip->optlen;
  348.   
  349.     *bpp = htonudp(&udp, *bpp, &ph);
  350.   
  351.     return status;
  352. }
  353. #endif
  354.   
  355. /* Given a network mask, return the number of contiguous 1-bits starting
  356.  * from the most significant bit.
  357.  */
  358. static int
  359. mask2width(mask)
  360. int32 mask;
  361. {
  362.     int width,i;
  363.   
  364.     width = 0;
  365.     for(i = 31;i >= 0;i--){
  366.         if(!(mask & (1L << i)))
  367.             break;
  368.         width++;
  369.     }
  370.     return width;
  371. }
  372. #endif /* BOOTP */
  373.   
  374.